package cn.xerllent.wxtp.rest;

import java.util.Map;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.xerllent.common.annotation.Log;
import cn.xerllent.common.exception.BadRequestException;
import cn.xerllent.wxtp.config.WxCpTpConfiguration;
import cn.xerllent.wxtp.config.WxCpTpProperties;
import cn.xerllent.wxtp.utils.ContactEnum;
import cn.xerllent.wxtp.utils.InfoTypeEnum;
import io.swagger.annotations.ApiOperation;
import lombok.val;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.crypto.WxCryptUtil;
import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
import me.chanjar.weixin.cp.api.impl.WxCpServiceOnTpImpl;
import me.chanjar.weixin.cp.bean.WxCpTpCorp;
import me.chanjar.weixin.cp.bean.WxCpTpPermanentCodeInfo;
import me.chanjar.weixin.cp.bean.WxCpTpXmlPackage;
import me.chanjar.weixin.cp.bean.message.WxCpTpXmlMessage;
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
import me.chanjar.weixin.cp.tp.service.WxCpTpService;
import me.chanjar.weixin.cp.util.crypto.WxCpTpCryptUtil;
import me.chanjar.weixin.cp.util.xml.XStreamTransformer;

/**
 * @author
 */
@RestController
@RequestMapping("/wxtp/callback")
@Slf4j
public class WxCpTpCallBackController {

	@Log("第三方服务商回调get验证")
	@ApiOperation("第三方服务商回调get验证")
	@GetMapping(produces = "text/plain;charset=utf-8")
	public String providerVerify(@RequestParam(name = "msg_signature", required = false) String signature,
			@RequestParam(name = "timestamp", required = false) String timestamp,
			@RequestParam(name = "nonce", required = false) String nonce,
			@RequestParam(name = "echostr", required = false) String echostr) {
		log.info("\n接收到来自微信服务器的认证消息：signature = [{}], timestamp = [{}], nonce = [{}], echostr = [{}]", signature,
				timestamp, nonce, echostr);

		if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
			throw new IllegalArgumentException("请求参数非法，请核实!");
		}

		try {
			WxCpTpProperties p = WxCpTpConfiguration.getProperties();
			return new WxCryptUtil(p.getProviderToken(), p.getProviderAesKey(), p.getCorpId()).decryptContent(signature,
					timestamp, nonce, echostr);
		} catch (Exception e) {
			log.error("Checking signature failed, and the reason is :" + e.getMessage());
			return "非法请求";
		}
	}
	
	@Log("第三方服务商通用回调post数据")
	@ApiOperation("第三方服务商通用回调post数据")
	@PostMapping(produces = "application/xml; charset=UTF-8")
	public String providerPost(@RequestBody String requestBody,
			@RequestParam("msg_signature") String signature, 
			@RequestParam("timestamp") String timestamp,
			@RequestParam("nonce") String nonce) {
		log.info("\n接收微信请求：[signature=[{}], timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ", signature, timestamp,
				nonce, requestBody);
			WxCpTpProperties p = WxCpTpConfiguration.getProperties();
			WxCryptUtil cryptUtil = new WxCryptUtil(p.getProviderToken(), p.getProviderAesKey(), p.getCorpId());
			
			String decryptMsgs = cryptUtil.decryptXml(signature,timestamp, nonce, requestBody);
			log.debug("\n消息解密后内容为：\n{} ", decryptMsgs);
			WxCpTpXmlMessage inMessage = WxCpTpXmlMessage.fromXml(decryptMsgs);

			//路由处理消息，在WxCpTpConfiguration初始化里配置路由,用默认dksb的路由来执行，因为没有通用路由
			WxCpXmlOutMessage outMessage = WxCpTpConfiguration.getRouter("dksb").route(inMessage);
	        if (Objects.nonNull(outMessage)) {
	        	//outMessage.toEncryptedXml(null)  参照这个
	            String plainXml = XStreamTransformer.toXml((Class)outMessage.getClass(), outMessage);
	            log.info("\n组装回复信息：{}", plainXml);
	            return cryptUtil.encrypt(plainXml);
	        }
	        return "success";
	}

	@Log("第三方服务商应用数据回调/指令回调get验证")
	@ApiOperation("第三方服务商应用数据回调/指令回调get验证")
	@GetMapping(value = "/{suiteName}", produces = "text/plain;charset=utf-8")
	public String suiteGet(@PathVariable String suiteName,
			@RequestParam(name = "msg_signature", required = false) String signature,
			@RequestParam(name = "timestamp", required = false) String timestamp,
			@RequestParam(name = "nonce", required = false) String nonce,
			@RequestParam(name = "echostr", required = false) String echostr,
			@RequestBody(required = false) String requestBody) {
		log.info("\n接收到来自微信服务器的认证消息：signature = [{}], timestamp = [{}], nonce = [{}], echostr = [{}], requestBody = [{}]", signature,
				timestamp, nonce, echostr, requestBody);

		if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
			throw new IllegalArgumentException("请求参数非法，请核实!");
		}

		final WxCpTpService wxCpTpService = WxCpTpConfiguration.getCpTpService(suiteName);
		if (wxCpTpService == null) {
			throw new IllegalArgumentException(String.format("未找到对应suiteName=[%d]的配置，请核实！", suiteName));
		}

		if (wxCpTpService.checkSignature(signature, timestamp, nonce, echostr)) {
			return new WxCpTpCryptUtil(wxCpTpService.getWxCpTpConfigStorage()).decrypt(echostr);
		}

		return "非法请求";
	}

	@Log("第三方服务商应用数据回调/指令回调Post")
	@ApiOperation("第三方服务商应用数据回调/指令回调Post")
	@PostMapping(value = "/{suiteName}", produces = "application/xml; charset=UTF-8")
	public String suiteDataPost(@PathVariable String suiteName, @RequestBody String requestBody,
			@RequestParam("msg_signature") String signature, @RequestParam("timestamp") String timestamp,
			@RequestParam("nonce") String nonce) {
		log.info("\n接收微信请求：[signature=[{}], timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ", signature, timestamp,
				nonce, requestBody);

		//WxCpTpXmlPackage tXmlPackage = WxCpTpXmlPackage.fromXml(requestBody);
		
		final WxCpTpService wxCpTpService = WxCpTpConfiguration.getCpTpService(suiteName);

		WxCpTpCryptUtil cryptUtil = new WxCpTpCryptUtil(wxCpTpService.getWxCpTpConfigStorage());
		
		String decryptMsgs = cryptUtil.decryptXml(signature,timestamp, nonce, requestBody);
		log.debug("\n消息解密后内容为：\n{} ", decryptMsgs);
		WxCpTpXmlMessage inMessage = WxCpTpXmlMessage.fromXml(decryptMsgs);

		//路由处理消息，在WxCpTpConfiguration初始化里配置路由
		WxCpXmlOutMessage outMessage = WxCpTpConfiguration.getRouter(suiteName).route(inMessage);
        if (Objects.nonNull(outMessage)) {
        	//outMessage.toEncryptedXml(null)  参照这个
            String plainXml = XStreamTransformer.toXml((Class)outMessage.getClass(), outMessage);
            log.info("\n组装回复信息：{}", plainXml);
            return cryptUtil.encrypt(plainXml);
        }
        return "success";
        
//		WxCpXmlOutMessage outMessage = WxCpTpConfiguration.getRouter(suiteName).route(inMessage);
//		if (outMessage == null) {
//			return "";
//		}
//
//		String out = outMessage.toEncryptedXml(new WxCpServiceOnTpImpl(wxCpTpService).getWxCpConfigStorage());
//		log.debug("\n组装回复信息：{}", out);
//		return out;
	}

//	@Log("第三方服务商应用指令回调Post")
//	@ApiOperation("第三方服务商应用指令回调Post")
//	@PostMapping(value = "/instruct/{suiteName}", produces = "application/xml; charset=UTF-8")
//	public String suiteinstructPost(@PathVariable String suiteName, @RequestBody String requestBody,
//			@RequestParam("msg_signature") String signature, @RequestParam("timestamp") String timestamp,
//			@RequestParam("nonce") String nonce) throws WxErrorException {
//		log.info("\n接收微信请求：[signature=[{}], timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ", signature, timestamp,
//				nonce, requestBody);
//
//		final WxCpTpService wxCpTpService = WxCpTpConfiguration.getCpTpService(suiteName);
//		
//		WxCpTpCryptUtil cryptUtil = new WxCpTpCryptUtil(wxCpTpService.getWxCpTpConfigStorage());
//
//		String decryptMsgs = cryptUtil.decryptXml(signature, timestamp, nonce, requestBody);
//		WxCpTpXmlMessage inMessage = WxCpTpXmlMessage.fromXml(decryptMsgs);
//		log.debug("\n消息解密后内容为：\n{} ", JSONUtil.toJsonStr(inMessage));
//		
//		//路由处理消息，在WxCpTpConfiguration初始化里配置路由
//		WxCpXmlOutMessage outMessage = WxCpTpConfiguration.getRouter(suiteName).route(inMessage);
//        if (Objects.nonNull(outMessage)) {
//            String plainXml = XStreamTransformer.toXml(WxCpXmlOutMessage.class, outMessage);
//            log.info("\n组装回复信息：{}", plainXml);
//            return cryptUtil.encrypt(plainXml);
//        }
//        return "success";

//		InfoTypeEnum infoTypeEnum = InfoTypeEnum.getByInstance(inMessage.getInfoType());
//		if (infoTypeEnum == null) {
//			throw new BadRequestException("不支持该类型操作");
//		}
//		log.info(infoTypeEnum.getDesc());
//		Map<String, Object> inMsgMap = inMessage.getAllFieldsMap();
//		switch (infoTypeEnum) {
//			// （每十分钟）推送ticket。ticket会实时变更，并用于后续接口的调用。
//			case SUITE_TICKET: {
//				String suitId = inMessage.getSuiteId();
//				String suiteTicket = inMessage.getSuiteTicket();
//				Integer timeStamp = Convert.toInt(inMessage.getTimeStamp());
//				log.info("推送ticket成功:\n{}", suiteTicket);
//				WxCpTpConfigStorage tpConfig = wxCpTpService.getWxCpTpConfigStorage();
//				tpConfig.updateSuiteTicket(suiteTicket, 20 * 60);
//				log.info("suit ticket缓存更新成功");
//	
//				String suitAccessToken = wxCpTpService.getSuiteAccessToken();
//				log.info("suitAccessToken:\\n{}", suitAccessToken);
//				break;
//			}
//			// 企业微信应用市场发起授权时，企业微信后台会推送授权成功通知
//			case CREATE_AUTH: {
//				log.info("创建授权：" + inMsgMap.toString());
//				String suiteId = inMessage.getSuiteId();
//				String authCode = inMessage.getAuthCode();
//				String timeStamp = inMessage.getTimeStamp();
//				WxCpTpPermanentCodeInfo permanentCode = wxCpTpService.getPermanentCodeInfo(authCode);
//				log.info("永久授权码：" + permanentCode);
//				// TODO: 保存到数据库
//				break;
//			}
//			// 企业微信应用市场发起变更授权
//			case CHANGE_AUTH: {
//				// TODO: 变更授权
//				break;
//			}
//			// 企业微信应用市场删除授权
//			case CANCEL_AUTH: {
//				// TODO: 删除授权
//				break;
//			}
//			// 通讯录变更
//			case CHANGE_CONTACT: {
//				String changeType = inMsgMap.get(InfoTypeEnum.SUB_TYPE).toString();
//				ContactEnum subEnum = ContactEnum.getByInstance(changeType);
//				if (ObjectUtil.isNull(subEnum)) {
//					throw new BadRequestException("该类型通讯录变更不存在");
//				}
//				log.info(subEnum.getDesc());
//				switch (subEnum) {
//				case CREATE_USER: {
//					break;
//				}
//				case UPDATE_USER: {
//					break;
//				}
//				case DELETE_USER: {
//					break;
//				}
//				case CREATE_PARTY: {
//					break;
//				}
//				case UPDATE_PARTY: {
//					break;
//				}
//				case DELETE_PARTY: {
//					break;
//				}
//				case UPDATE_TAG: {
//					break;
//				}
//				default: {
//					break;
//				}
//				}
//				break;
//			}
//			case CHANGE_EXTERNAL_CONTACT: {// 外部联系人事件
//				log.info("外部联系人");
//				String changeType = inMsgMap.get(InfoTypeEnum.SUB_TYPE).toString();
//				ContactEnum subEnum = ContactEnum.getByInstance(changeType);
//				if (ObjectUtil.isNull(subEnum)) {
//					throw new BadRequestException("该类型CHANGE_EXTERNAL_CONTACT不存在");
//				}
//				switch (subEnum) {
//					case CREATE_USER: {
//						log.info("添加客户" + inMsgMap.toString());
//						String externalUserID = inMsgMap.get("ExternalUserID").toString();
//						String welcomeCode = inMsgMap.get("WelcomeCode").toString();
//						if (StringUtils.isEmpty(welcomeCode)) {
//							log.warn("welcomeCode没获取到，用户可能已经设置了欢迎语！！！");
//							break;
//						}
//						String userID = inMsgMap.get("UserID").toString();
//						String suiteId = inMsgMap.get("SuiteId").toString();
//						String authCorpId = inMsgMap.get("AuthCorpId").toString();
//						System.out.println("欢迎code：" + welcomeCode);
//						// TODO: 保存到数据库sendWelcome(tpService, welcomeCode);
//						break;
//					}
//					default: {
//						break;
//					}
//				}
//			}
//			case CHANGE_EXTERNAL_CHAT: {
//				break;
//			}
//			case CHANGE_EXTERNAL_TAG: {
//				break;
//			}
//			case CHANGE_SCHOOL_CONTACT: {
//				break;
//			}
//			case SHARE_AGENT_CHANGE: {
//				break;
//			}
//			case REGISTER_CORP: {
//				break;
//			}
//			case BATCH_JOB_RESULT: {
//				break;
//			}
//			default: {
//				break;
//			}
//		}
//		return "success";
//	}

}
